<template>
  <div class="number-scroll-container">
    <div class="number-scroll" ref="scrollContainer">
      <template v-for="(digit, index) in displayDigits" :key="index">
        <div class="digit-column" v-if="digit.type === 'digit'">
          <div class="digit-wrapper" :style="getTransformStyle(digit.value, digit.oldValue)">
            <div v-for="num in 10" :key="num" class="digit">{{ num - 1 }}</div>
          </div>
        </div>
        <div class="separator" v-else>{{ digit.value }}</div>
      </template>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, computed, watch, onMounted, PropType } from 'vue'

interface Digit {
  type: 'digit' | 'separator';
  value: string | number;
  oldValue?: number;
}

export default defineComponent({
  name: 'NumberScroll',
  props: {
    value: {
      type: Number,
      required: true,
      default: 0
    },
    duration: {
      type: Number,
      default: 1000
    },
    format: {
      type: String,
      default: ''
    },
    easing: {
      type: String,
      default: 'cubic-bezier(0.25, 0.1, 0.25, 1)'
    }
  },
  setup(props) {
    const scrollContainer = ref<HTMLElement | null>(null);
    const oldValue = ref(props.value);
    const displayDigits = ref<Digit[]>([]);

    // Format the number according to the format string
    const formatNumber = (num: number, format: string): string => {
      if (!format) {
        return num.toString();
      }

      // Handle common format patterns
      if (format === '#,##0') {
        return num.toLocaleString('en-US', { maximumFractionDigits: 0 });
      }
      
      if (format === '#,##0.00') {
        return num.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
      }
      
      if (format === '$#,##0.00') {
        return num.toLocaleString('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 2 });
      }

      // Default fallback
      return num.toString();
    };

    // Parse the formatted string into an array of digits and separators
    const parseFormattedNumber = (formattedStr: string): Digit[] => {
      const result: Digit[] = [];
      const digits = '0123456789';
      
      for (let i = 0; i < formattedStr.length; i++) {
        const char = formattedStr[i];
        if (digits.includes(char)) {
          result.push({
            type: 'digit',
            value: parseInt(char),
            oldValue: 0
          });
        } else {
          result.push({
            type: 'separator',
            value: char
          });
        }
      }
      
      return result;
    };

    // Update the digits array when the value changes
    const updateDigits = () => {
      const formattedNew = formatNumber(props.value, props.format);
      const formattedOld = formatNumber(oldValue.value, props.format);
      
      const newDigits = parseFormattedNumber(formattedNew);
      
      // Map old values to new digits where possible
      if (formattedOld.length === formattedNew.length) {
        const oldDigits = parseFormattedNumber(formattedOld);
        
        for (let i = 0; i < newDigits.length; i++) {
          if (newDigits[i].type === 'digit' && oldDigits[i].type === 'digit') {
            newDigits[i].oldValue = oldDigits[i].value as number;
          }
        }
      }
      
      displayDigits.value = newDigits;
      oldValue.value = props.value;
    };

    // Calculate transform style for the digit animation
    const getTransformStyle = (newVal: string | number, oldVal: number = 0) => {
      if (typeof newVal !== 'number') return {};
      
      const percentage = newVal * 10 + '%';
      const oldPercentage = oldVal * 10 + '%';
      
      return {
        transform: `translateY(-${percentage})`,
        transition: `transform ${props.duration}ms ${props.easing}`,
        '--old-transform': `translateY(-${oldPercentage})`
      };
    };

    // Watch for value changes
    watch(() => props.value, () => {
      updateDigits();
    });

    // Initialize on mount
    onMounted(() => {
      updateDigits();
    });

    return {
      scrollContainer,
      displayDigits,
      getTransformStyle
    };
  }
});
</script>

<style scoped>
.number-scroll-container {
  display: inline-block;
  overflow: hidden;
}

.number-scroll {
  display: flex;
  align-items: center;
  height: 1em;
  line-height: 1;
}

.digit-column {
  position: relative;
  overflow: hidden;
  height: 1em;
  width: 0.6em;
}

.digit-wrapper {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  transform: translateY(0);
  transform: var(--old-transform, translateY(0));
}

.digit {
  height: 1em;
  text-align: center;
}

.separator {
  padding: 0 0.1em;
}
</style>